package org.jeecg.common.util;

import lombok.experimental.UtilityClass;
import org.apache.commons.lang3.StringUtils;
import org.springframework.lang.Nullable;

import java.text.ParseException;
import java.util.Calendar;
import java.util.Date;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 日期工具类
 *
 * @author Kai
 */
@UtilityClass
public class DateFormatUtils extends org.apache.commons.lang3.time.DateUtils {

    public static final String ISO_PATTERN = "yyyy-MM-dd'T'HH:mm:ss.SSSZ";

    public static final String DEFAULT_DATE_PATTERN = "yyyy-MM-dd";

    public static final String DEFAULT_TIME_PATTERN = "yyyy-MM-dd HH:mm:ss";

    String pattern = "\\((\\d+)\\)";

    private static final String[] COMMON_DATE_PATTERNS = {ISO_PATTERN, DEFAULT_DATE_PATTERN, DEFAULT_TIME_PATTERN,
        "yyyy/MM/dd", "yyyyMMdd", "yyyy-MM-dd HH:mm", "yyyy/MM/dd HH:mm:ss", "yyyy/MM/dd HH:mm"};

    /**
     * 当前时间，格式 yyyy-MM-dd HH:mm:ss
     *
     * @return 当前时间的标准形式字符串
     */
    public static String now() {
        return org.apache.commons.lang3.time.DateFormatUtils.format(new Date(), DEFAULT_TIME_PATTERN);
    }

    /**
     * 当前日期，格式 yyyy-MM-dd
     *
     * @return 当前日期的标准形式字符串
     */
    public static String today() {
        return org.apache.commons.lang3.time.DateFormatUtils.format(new Date(), DEFAULT_DATE_PATTERN);
    }

    /**
     * 判断两个日期相差的时长，只保留绝对值
     *
     * @param begin 起始日期
     * @param end   结束日期
     * @return 日期差（毫秒）
     */
    public static long between(Date begin, Date end) {
        if (begin == null || end == null) {
            return 0L;
        }
        return Math.abs(end.getTime() - begin.getTime());
    }

    /**
     * 根据特定格式格式化日期
     *
     * @param date    日期对象
     * @param pattern 日期格式
     * @return 格式化后的字符串
     */
    public static String format(Date date, String pattern) {
        return org.apache.commons.lang3.time.DateFormatUtils.format(date, pattern);
    }

    /**
     * 将特殊格式的日期转化
     * @param date 日期格式为/Date(1672730511000)/
     * @return 格式化后的字符串
     */
    public static String matcherFormat(String date){
        if(StringUtils.isBlank(date)){
            return date;
        }
        Pattern r = Pattern.compile(pattern);
        Matcher m = r.matcher(date);
        String dateStr = "";
        if (m.find()) {
            long time = Long.parseLong(m.group(1));
            dateStr = org.apache.commons.lang3.time.DateFormatUtils.format(time,DEFAULT_TIME_PATTERN);
        }
        return dateStr;
    }

    /**
     * 将日期字符串转换为Date对象
     *
     * @param dateStr 日期字符串
     * @return 日期
     */
    @Nullable
    public static Date parse(String dateStr) {
        if (dateStr == null) {
            return null;
        }

        Date parsed;
        try {
            parsed = parseDate(dateStr, COMMON_DATE_PATTERNS);
        } catch (ParseException e) {
            throw new IllegalArgumentException("invalid date: " + dateStr);
        }

        return parsed;
    }

    /**
     * 获取某天的开始时间
     *
     * @param dateStr 日期字符串
     * @return 日期
     */
    public static Date beginOfDay(String dateStr) {
        return beginOfDay(parse(dateStr));
    }

    /**
     * 获取某天的开始时间
     *
     * @param date 日期
     * @return 日期
     */
    public static Date beginOfDay(final Date date) {
        Calendar c = Calendar.getInstance();
        c.setTime(date);
        beginOfDay(c);
        return c.getTime();
    }

    /**
     * 获取某天的结束时间
     *
     * @param dateStr 日期字符串
     * @return 日期
     */
    public static Date endOfDay(String dateStr) {
        return endOfDay(parse(dateStr));
    }

    /**
     * 获取某天的结束时间
     *
     * @param date 日期
     * @return 日期
     */
    public static Date endOfDay(final Date date) {
        Calendar c = Calendar.getInstance();
        c.setTime(date);
        endOfDay(c);
        return c.getTime();
    }

    /**
     * 获取某周的开始时间
     *
     * @param dateStr 日期字符串
     * @return 日期
     */
    public static Date beginOfWeek(final String dateStr) {
        return beginOfWeek(parse(dateStr));
    }

    /**
     * 获取某周的开始时间
     *
     * @param date 日期
     * @return 日期
     */
    public static Date beginOfWeek(final Date date) {
        Calendar c = Calendar.getInstance();
        c.setTime(date);
        c.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
        beginOfDay(c);
        return c.getTime();
    }

    /**
     * 获取某周的结束时间
     *
     * @param dateStr 日期字符串
     * @return 日期
     */
    public static Date endOfWeek(String dateStr) {
        return endOfWeek(parse(dateStr));
    }

    /**
     * 获取某周的结束时间
     *
     * @param date 日期
     * @return 日期
     */
    public static Date endOfWeek(final Date date) {
        Calendar c = Calendar.getInstance();
        c.setTime(date);
        c.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
        c.add(Calendar.DAY_OF_YEAR, 6);
        endOfDay(c);
        return c.getTime();
    }

    /**
     * 获取某月的开始时间
     *
     * @param dateStr 日期字符串
     * @return 日期
     */
    public static Date beginOfMonth(final String dateStr) {
        return beginOfMonth(parse(dateStr));
    }

    /**
     * 获取某月的开始时间
     *
     * @param date 日期
     * @return 日期
     */
    public static Date beginOfMonth(final Date date) {
        Calendar c = Calendar.getInstance();
        c.setTime(date);
        c.set(Calendar.DAY_OF_MONTH, 1);
        beginOfDay(c);
        return c.getTime();
    }

    /**
     * 获取某月的结束时间
     *
     * @param dateStr 日期字符串
     * @return 日期
     */
    public static Date endOfMonth(String dateStr) {
        return endOfMonth(parse(dateStr));
    }

    /**
     * 获取某月的结束时间
     *
     * @param date 日期
     * @return 日期
     */
    public static Date endOfMonth(final Date date) {
        Calendar c = Calendar.getInstance();
        c.setTime(date);
        c.set(Calendar.DAY_OF_MONTH, 1);
        c.add(Calendar.MONTH, 1);
        c.add(Calendar.DAY_OF_YEAR, -1);
        endOfDay(c);
        return c.getTime();
    }

    /**
     * 获取某年的开始时间
     *
     * @param dateStr 日期字符串
     * @return 日期
     */
    public static Date beginOfYear(final String dateStr) {
        return beginOfYear(parse(dateStr));
    }

    /**
     * 获取某年的开始时间
     *
     * @param date 日期
     * @return 日期
     */
    public static Date beginOfYear(final Date date) {
        Calendar c = Calendar.getInstance();
        c.setTime(date);
        c.set(Calendar.DAY_OF_YEAR, 1);
        beginOfDay(c);
        return c.getTime();
    }

    /**
     * 获取某年的结束时间
     *
     * @param dateStr 日期字符串
     * @return 日期
     */
    public static Date endOfYear(String dateStr) {
        return endOfYear(parse(dateStr));
    }

    /**
     * 获取某年的结束时间
     *
     * @param date 日期
     * @return 日期
     */
    public static Date endOfYear(final Date date) {
        Calendar c = Calendar.getInstance();
        c.setTime(date);
        c.set(Calendar.DAY_OF_YEAR, 1);
        c.add(Calendar.DAY_OF_YEAR, -1);
        c.add(Calendar.YEAR, 1);
        endOfDay(c);
        return c.getTime();
    }

    private static void beginOfDay(Calendar calendar) {
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);
    }

    private static void endOfDay(Calendar calendar) {
        calendar.set(Calendar.HOUR_OF_DAY, 23);
        calendar.set(Calendar.MINUTE, 59);
        calendar.set(Calendar.SECOND, 59);
        calendar.set(Calendar.MILLISECOND, 999);
    }

    public static void main(String[] args) {
        System.out.printf(DateFormatUtils.format(DateFormatUtils.beginOfDay(new Date()),DateFormatUtils.DEFAULT_TIME_PATTERN));
    }
}
